//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Common Core Extensions
//===============================================================================

using System;
using System.IO;
using System.Reflection;
using System.Globalization;
using System.Windows.Forms;
using System.Diagnostics.CodeAnalysis;
using EntLibContrib.Common.Properties;

namespace EntLibContrib.Common.Configuration.Design.Editors
{
	/// <summary>
	/// Represents the UI for the assembly selector dialog.
	/// </summary>
  public partial class ResourceSelectorUI : Form
  {
		#region Constants
    private const string AssemblyFileFilter = "Assemblies (*.exe;*.dll) | *.exe;*.dll";
    #endregion

		#region Fields
		private OpenFileDialog openFileDialog = new OpenFileDialog();
    private ResourceSelector selector;
		#endregion

		#region Properties
		/// <summary>
		/// Gets the <see cref="AssemblyResourceName"/> selected for use.
		/// </summary>
		/// <value>The <see cref="AssemblyResourceName"/> selected for use.</value>
		public AssemblyResourceName SelectedResource
		{
			get { return this.treeView.SelectedNode.Tag as AssemblyResourceName; }
		}

		/// <summary>
		/// Gets the <see cref="ImageList"/> for the types.
		/// </summary>
		/// <value>The <see cref="ImageList"/> for the types.</value>
		internal ImageList ResourceImageList
		{
			get { return this.resourceImageList; }
		}
		#endregion

		#region Construction
		/// <summary>
		/// Initialize a new instance of the <see cref="ResourceSelectorUI"/> class.
		/// </summary>
    public ResourceSelectorUI()
    {
      InitializeComponent();
      openFileDialog.Filter = AssemblyFileFilter;
    }

		/// <summary>
		/// Initialize a new instance of the <see cref="ResourceSelectorUI"/> class.
		/// </summary>
		/// <param name="currentAssemblyResourceName">Name of the current assembly resource.</param>
		public ResourceSelectorUI(AssemblyResourceName currentAssemblyResourceName)
			: this()
		{
			this.openFileDialog.DereferenceLinks = false;
			this.selector = new ResourceSelector(currentAssemblyResourceName, this.treeView);
		}
		#endregion

		#region Event Handlers
		/// <summary>
		/// Called when the browse button is clicked.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
		private void OnBrowseButtonClick(object sender, EventArgs e)
    {
			LoadAssembly(() =>
				{
					DialogResult result = this.openFileDialog.ShowDialog(this);
					if (result == DialogResult.OK)
					{
						string originalAssemblyFileName = this.openFileDialog.FileName;

						using (AssemblyLoader loader = new AssemblyLoader(originalAssemblyFileName, Path.GetDirectoryName(originalAssemblyFileName)))
						{
							return Assembly.LoadFrom(loader.CopiedAssemblyPath);
						}
					}
					else
						return null;
				});
		}

		/// <summary>
		/// Called when a node on the tree view is double-clicked.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    private void OnTreeViewDoubleClick(object sender, EventArgs e)
    {
			this.OnOkButtonClick(this, EventArgs.Empty);
    }

		/// <summary>
		/// Called when the OK button is clicked.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    private void OnOkButtonClick(object sender, EventArgs e)
    {
			if (SelectedResource == null)
				DisplayMessageBox(InternalResources.ExceptionNoResourceSelectedMessage, InternalResources.ExceptionNoResourceSelectedCaption, MessageBoxIcon.Exclamation);
			else
			{
				DialogResult = DialogResult.OK;
				Close();
			}
		}

		/// <summary>
		/// Called when the cancel button is clicked.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OnCancelButtonClick(object sender, EventArgs e)
		{
			DialogResult = DialogResult.Cancel;
			Close();
		}

		/// <summary>
		/// Called when the Expand button is clicked.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OnExpandButtonClick(object sender, EventArgs e)
		{
			this.selector.ExpandAssemblyNodes();
		}

		/// <summary>
		/// Called when the Collapse button is clicked.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OnCollapseButtonClick(object sender, EventArgs e)
		{
			this.selector.CollapseAssemblyNodes();
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Loads an assembly into the tree view.
		/// </summary>
		/// <param name="loadAssemblyFromFile">The load assembly from file function.</param>
		private void LoadAssembly(Func<Assembly> loadAssemblyFromFile)
		{
			Assembly assembly = null;

			try
			{
				if ((assembly = loadAssemblyFromFile()) != null)
				{
					try
					{
						this.treeView.BeginUpdate();

						TreeNode assemblyNode = this.selector.LoadTreeView(assembly);
						if (assemblyNode == null)
							DisplayMessageBox(string.Format(CultureInfo.CurrentCulture, InternalResources.NoResourcesFoundInAssemblyErrorMessage, assembly.GetName().Name), InternalResources.NoResourcesFoundInAssemblyCaption);
						else
							this.selector.PositionTreeView(assemblyNode);
					}
					finally
					{
						this.treeView.EndUpdate();
					}
				}
			}
			catch (FileNotFoundException ex)
			{
				DisplayMessageBox(string.Format(CultureInfo.CurrentCulture, InternalResources.AssemblyLoadFailedErrorMessage, ex.Message), string.Empty);
				return;
			}
			catch (BadImageFormatException ex)
			{
				DisplayMessageBox(string.Format(CultureInfo.CurrentCulture, InternalResources.AssemblyLoadFailedErrorMessage, ex.Message), string.Empty);
				return;
			}
		}

		/// <summary>
		/// Displays the message box.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="caption">The caption.</param>
		private void DisplayMessageBox(string message, string caption)
		{
			DisplayMessageBox(message, caption, MessageBoxIcon.Information);
		}

		/// <summary>
		/// Displays the message box.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="caption">The caption.</param>
		/// <param name="icon">The icon.</param>
		private void DisplayMessageBox(string message, string caption, MessageBoxIcon icon)
		{
			MessageBoxOptions options = (MessageBoxOptions)0;

			if (RightToLeft == RightToLeft.Yes)
				options = MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign;

			MessageBox.Show(message, caption, MessageBoxButtons.OK, icon, MessageBoxDefaultButton.Button1, options);
		}
		#endregion
	}
}